//
//  GatherLive.m
//  LiveGather
//
//  Created by macintosh on 16/9/12.
//  Copyright © 2016年 Yue Shen. All rights reserved.
//

#import "GatherLive.h"
#import <LFLiveKit/LFLiveKit.h>
#import "UIDevice+InterfaceOrientation.h"
#import "UIControl+YYAdd.h"
#import "UIView+YYAdd.h"
#import "MonitorInfo.h"
#import "GatherInfo.h"
#import "GatherAuthorization.h"

#import "GatherPreparing.h"
#import "GatherControlView.h"
#import "GatherSetting.h"

@interface GatherLive () <LFLiveSessionDelegate>

@property (nonatomic, weak) UIButton *muteBtn;
@property (nonatomic, weak) UIButton *beautyBtn;
@property (nonatomic, weak) UIButton *rotationBtn;
@property (nonatomic, weak) UIButton *torchBtn;
@property (nonatomic, weak) UIButton *barrageBtn;

@property (nonatomic, strong) UIPinchGestureRecognizer *pinchGesture;
@property (nonatomic, assign) CGFloat prePinchScale;

@property (nonatomic, strong) NSMutableArray *buttons;
@property (nonatomic, strong) LFLiveSession *session;

@property (nonatomic, strong) GatherPreparing *preparingView;
@property (nonatomic, strong) GatherControlView *controlView;

@property (nonatomic, strong) MonitorInfo *monitorInfo;
@property (nonatomic, strong) GatherInfo *gatherInfo;

@property (nonatomic, strong) NSString *rtmpUrl;
@property (nonatomic, assign) BOOL isFirstLoad;
@property (nonatomic, assign) BOOL gatherInfoChanged;
@property (nonatomic, assign) BOOL isEndingLive;
@property (nonatomic, assign) BOOL isStartingLive;
@property (nonatomic, assign) BOOL liveOrentationChanged;

@property (nonatomic, assign) CGSize videoSize;

@end

@implementation GatherLive

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

- (BOOL)prefersStatusBarHidden {
    return NO;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _isFirstLoad = YES;
    _gatherInfoChanged = NO;
    _isEndingLive = NO;
    _isStartingLive = NO;
    _liveOrentationChanged = NO;
    _videoSize = self.view.size;
    _gatherInfo = [GatherInfo gatherInfo];
    self.view.backgroundColor = [UIColor blackColor];
    [self.view addGestureRecognizer:self.pinchGesture];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    [self.navigationController setNavigationBarHidden:YES];

    if (_isFirstLoad) {
        _isFirstLoad = NO;
        [self.view addSubview:self.preparingView];
        [self initButtons];
        self.controlView.barButtons = _buttons;
        [self buildSession];
    } else {
        _session.preView = self.view;
        _session.captureDevicePosition = _gatherInfo.isFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
        self.session.running = YES;
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    
    self.session.running = NO;
    [self.session stopLive];
}

- (void)initButtons
{
    _buttons = [NSMutableArray array];
    @weakify(self);
    
    UIButton *cameraBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [cameraBtn setImage:[UIImage imageNamed:@"the_camera"] forState:UIControlStateNormal];
    [cameraBtn addBlockForControlEvents:UIControlEventTouchUpInside block:^(UIButton *  _Nonnull sender) {
        @strongify(self);
        self.session.captureDevicePosition = (self.session.captureDevicePosition == AVCaptureDevicePositionBack) ? (self.torchBtn.enabled = NO, self.torchBtn.selected = NO, AVCaptureDevicePositionFront) : (self.torchBtn.enabled = YES, AVCaptureDevicePositionBack);
        self.gatherInfo.isFrontCamera = self.session.captureDevicePosition == AVCaptureDevicePositionFront ? YES : NO;
        if (self.gatherInfo.showLogo) {
            [self.controlView layoutWaterViewByCanvasSize:self.videoSize flipped:self.gatherInfo.isFrontCamera];
            //改变waterView的frame的同时，还需要重新添加到容器中
            self.session.warterMarkView = self.controlView.waterView;
        }
    }];
    
    //这里没有电筒的图片，先临时代替
    UIButton *torchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [torchBtn setImage:[UIImage imageNamed:@"flashlight"] forState:UIControlStateNormal];
    [torchBtn setImage:[UIImage imageNamed:@"ban_flashlight"] forState:UIControlStateSelected];
    [torchBtn addBlockForControlEvents:UIControlEventTouchUpInside block:^(UIButton *  _Nonnull sender) {
        @strongify(self);
        sender.selected = !sender.isSelected;
        self.gatherInfo.openTorch = sender.isSelected;
        self.session.torch = sender.isSelected;
    }];
    _torchBtn = torchBtn;
    
    UIButton *muteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [muteBtn setImage:[UIImage imageNamed:@"ban_recording"] forState:UIControlStateNormal];
    [muteBtn setImage:[UIImage imageNamed:@"recording"] forState:UIControlStateSelected];
    [muteBtn addBlockForControlEvents:UIControlEventTouchUpInside block:^(UIButton *  _Nonnull sender) {
        @strongify(self);
        sender.selected = !sender.isSelected;
        self.gatherInfo.isMute = sender.isSelected;
        self.session.muted = sender.isSelected;
    }];
    _muteBtn = muteBtn;
    
    UIButton *beautyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [beautyBtn setImage:[UIImage imageNamed:@"ban_skin_care"] forState:UIControlStateNormal];
    [beautyBtn setImage:[UIImage imageNamed:@"skin_care"] forState:UIControlStateSelected];
    [beautyBtn addBlockForControlEvents:UIControlEventTouchUpInside block:^(UIButton *  _Nonnull sender) {
        @strongify(self);
        sender.selected = !sender.isSelected;
        self.gatherInfo.openBeauty = sender.isSelected;
        self.session.beautyFace = sender.isSelected;
    }];
    _beautyBtn = beautyBtn;
    
    UIButton *rotationBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [rotationBtn setImage:[UIImage imageNamed:@"ban_switch"] forState:UIControlStateNormal];
    [rotationBtn setImage:[UIImage imageNamed:@"switch"] forState:UIControlStateSelected];
    [rotationBtn addBlockForControlEvents:UIControlEventTouchUpInside block:^(UIButton *  _Nonnull sender) {
        @strongify(self);
        sender.selected = !sender.isSelected;
        self.gatherInfo.isLandscape = sender.isSelected;
        self.session.running = NO;
        [self.session stopLive];
        self.session.preView = nil;
        
        [[UIDevice currentDevice] setOrientation:sender.isSelected ? UIDeviceOrientationLandscapeLeft : UIDeviceOrientationPortrait];
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self rebuildAndConfigSession];
            LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
            stream.url = self.rtmpUrl;
            [self.session startLive:stream];
        });
    }];
    _rotationBtn = rotationBtn;
    
    //这里没有电筒的图片，先临时代替
    UIButton *barrageBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [barrageBtn setImage:[UIImage imageNamed:@"barrage"] forState:UIControlStateNormal];
    [barrageBtn setImage:[UIImage imageNamed:@"ban_barrage"] forState:UIControlStateSelected];
    [barrageBtn addBlockForControlEvents:UIControlEventTouchUpInside block:^(UIButton *  _Nonnull sender) {
        @strongify(self);
        sender.selected = !sender.isSelected;
    }];
    _barrageBtn = barrageBtn;
    
    [_buttons addObject:cameraBtn];
    [_buttons addObject:torchBtn];
    [_buttons addObject:muteBtn];
    [_buttons addObject:beautyBtn];
    [_buttons addObject:rotationBtn];
    [_buttons addObject:barrageBtn];
}

#pragma mark - LFLive

- (LFLiveAudioConfiguration *)audioConfiguration
{
    LFLiveAudioQuality quality = LFLiveAudioQuality_Default;
    
    if (_gatherInfo.audioRate == 32) {
        quality = LFLiveAudioQuality_Low;
    } else if (_gatherInfo.audioRate == 64) {
        quality = LFLiveAudioQuality_Medium;
    } else if (_gatherInfo.audioRate == 96) {
        quality = LFLiveAudioQuality_High;
    } else if (_gatherInfo.audioRate == 128) {
        quality = LFLiveAudioQuality_VeryHigh;
    }
    
    return [LFLiveAudioConfiguration defaultConfigurationForQuality:quality];
}

- (LFLiveVideoConfiguration *)videoConfigurationIsLandscape
{
    return [LFLiveVideoConfiguration configurationWithRes:_gatherInfo.resolution == 720 ? YES : NO rate:_gatherInfo.videoRate * 1000 fps:_gatherInfo.fps outputImageOrientation:_gatherInfo.isLandscape ? UIInterfaceOrientationLandscapeRight : UIInterfaceOrientationPortrait];
}

- (void)rebuildSession
{
    if (!_session) {
        [self buildSession];
    } else {
        LFLiveSession *tmpSession = _session;
        tmpSession.running = NO;
        tmpSession.preView = nil;
        tmpSession.warterMarkView = nil;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            [tmpSession class];
        });
        
        [self buildSession];
    }
}

- (void)buildSession
{
    LFLiveVideoConfiguration *configuration = [LFLiveVideoConfiguration configurationWithRes:NO rate:800 * 1000 fps:25 outputImageOrientation:UIInterfaceOrientationPortrait];
    _session = [[LFLiveSession alloc] initWithAudioConfiguration:[LFLiveAudioConfiguration defaultConfigurationForQuality:LFLiveAudioQuality_Low] videoConfiguration:configuration];
    
    self.videoSize = configuration.videoSize;
    self.pinchGesture.scale = 0;
    _session.delegate = self;
    _session.preView = self.view;
    _session.beautyFace = NO;
    _session.beautyLevel = 0.8;
    _session.brightLevel = 0.8;
    _beautyBtn.selected = NO;
    _session.captureDevicePosition = _gatherInfo.isFrontCamera ? AVCaptureDevicePositionFront :AVCaptureDevicePositionBack;
    _session.muted = _gatherInfo.isMute;
    _session.torch = NO;
    _session.warterMarkView = nil;
    _session.showDebugInfo = YES;
    _session.running = YES;
}

- (void)updateSession
{
    LFLiveVideoConfiguration *configuration = [self videoConfigurationIsLandscape];
    _session = [[LFLiveSession alloc] initWithAudioConfiguration:[self audioConfiguration] videoConfiguration:configuration];
    
    _session.delegate = self;
    _session.preView = self.view;
    _session.beautyLevel = 0.8;
    _session.brightLevel = 0.8;
    [self configSessionWithVideoConfiguration:configuration];
    _session.showDebugInfo = YES;
    _session.running = YES;
}

- (void)configSessionWithVideoConfiguration:(LFLiveVideoConfiguration *)videoConfiguration
{
    self.videoSize = videoConfiguration.videoSize;
    self.pinchGesture.scale = 0;
    _session.captureDevicePosition = _gatherInfo.isFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
    _session.beautyFace = _gatherInfo.openBeauty;
    _beautyBtn.selected = _session.beautyFace;
    _session.muted = _gatherInfo.isMute;
    
    if (_gatherInfo.showLogo) {
        [self.controlView layoutWaterViewByCanvasSize:self.videoSize flipped:self.gatherInfo.isFrontCamera];
        UIView *waterView = self.controlView.waterView;
        _session.warterMarkView = waterView;
    }
    
    if (_gatherInfo.isFrontCamera == NO && _gatherInfo.openTorch) {
        _session.torch = YES;
        _torchBtn.selected = YES;
    }
}

- (void)rebuildAndConfigSession
{
    if (!_session) {
        [self updateSession];
    } else {
        LFLiveSession *tmpSession = _session;
        tmpSession.running = NO;
        tmpSession.preView = nil;
        tmpSession.warterMarkView = nil;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
            [tmpSession class];
        });
        
        [self updateSession];
    }
}

- (void)prepareToStartLiveWithUrl:(NSString *)url
{
    [self rebuildAndConfigSession];
    self.controlView.resStr = [NSString stringWithFormat:@"%ldp", self.gatherInfo.resolution];
    self.rtmpUrl = url;
    self.pinchGesture.enabled = YES;
    [self.view addSubview:self.controlView];
    [self.controlView updateLiveBtnState:YES];
    [self.preparingView removeFromSuperview];
    LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
    stream.url = self.rtmpUrl;
    [self.session startLive:stream];
}

- (void)prepareToEndLive
{
    [self rebuildSession];
    self.pinchGesture.enabled = NO;
    [self.view addSubview:self.preparingView];
    [self.controlView resetDisplayInfo];
    [self.controlView removeFromSuperview];
}

#pragma mark LFLiveSessionDelegate
/** live status changed will callback */
- (void)liveSession:(nullable LFLiveSession *)session liveStateDidChange:(LFLiveState)state{
    GatherMonitorState monitorState;
    switch (state) {
        case LFLiveReady:
            monitorState = GatherMonitorReady;
            break;
        case LFLivePending:
            monitorState = GatherMonitorPending;
            break;
        case LFLiveStart:
            monitorState = GatherMonitorStart;
            break;
        case LFLiveStop:
            monitorState = GatherMonitorStop;
            break;
        case LFLiveError:
            monitorState = GatherMonitorError;
            break;
        default:
            monitorState = GatherMonitorUnknown;
            break;
    }
    
    self.controlView.state = monitorState;
}

/** live debug info callback */
- (void)liveSession:(nullable LFLiveSession *)session debugInfo:(nullable LFLiveDebug*)debugInfo{
    [self.monitorInfo setMonitorInfoWithVRate:debugInfo.currentVideoBandwidth / 1024 aRate:debugInfo.currentAudioBandwidth / 1024 fps:debugInfo.currentCapturedVideoCount];
    [self.controlView updateMonitorWithMonitorInfo:_monitorInfo];
}

/** callback socket errorcode */
- (void)liveSession:(nullable LFLiveSession*)session errorCode:(LFLiveSocketErrorCode)errorCode{
    NSLog(@"----------------------%ld", errorCode);
    self.controlView.state = GatherMonitorError;
}

#pragma mark - gesture

- (void)pinch:(UIPinchGestureRecognizer *)sender {
    switch (sender.state) {
        case UIGestureRecognizerStateBegan:
            _prePinchScale = sender.scale;
            break;
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded:
            _prePinchScale = 0;
            break;
        case UIGestureRecognizerStateChanged:
        {
            CGFloat scale = _session.zoomScale + (sender.scale - _prePinchScale);
            scale = MIN(MAX(1, scale), 4);
            _session.zoomScale = scale;
            _prePinchScale = sender.scale;
        }
            break;
        default:
            break;
    }
}

#pragma mark - rotation

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return !_rotationBtn.isSelected ? UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskLandscapeRight;
}

- (BOOL)shouldAutorotate
{
    return YES;
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
    
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
        self.controlView.frame = (CGRect){CGPointZero, size};
        self.preparingView.frame = (CGRect){CGPointZero, size};
        
        if (size.width > size.height) {
            [self.controlView updateLayoutOfSubviewsWithOrentationPortrait:NO];
        } else {
            [self.controlView updateLayoutOfSubviewsWithOrentationPortrait:YES];
        }
        
        if (self.liveOrentationChanged) {
            self.liveOrentationChanged = NO;
        }
        
        if (self.isStartingLive) {
            self.isStartingLive = NO;
            self.preparingView.alpha = 0;
            self.controlView.alpha = 1;
        }
        
        if (self.isEndingLive) {
            self.isEndingLive = NO;
            self.controlView.alpha = 0;
            self.preparingView.alpha = 0.4;
        }
    } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
    }];
}

#pragma mark - setter

- (void)setGatherInfo:(GatherInfo *)gatherInfo
{
    if (![_gatherInfo isEqual:gatherInfo]) {
        _gatherInfo = gatherInfo;
        _gatherInfoChanged = YES;
    }
}

#pragma mark - getter

- (GatherPreparing *)preparingView
{
    if (!_preparingView) {
        _preparingView = [[NSBundle mainBundle] loadNibNamed:@"GatherPreparing" owner:nil options:nil][0];
        _preparingView.frame = self.view.bounds;
        
        @weakify(self);
        //跳转到设置界面
        _preparingView.gatherSetting = ^{
            @strongify(self);
            self.session.running = NO;
            self.session.preView = nil;
            GatherSetting *gatherSetting = [GatherSetting gatherSettingWithGatherInfo:self.gatherInfo];
            
            @weakify(self);
            gatherSetting.goBack = ^ (GatherInfo *info) {
                @strongify(self);
                
                self.gatherInfo = info;
                self.torchBtn.enabled = !self.gatherInfo.isFrontCamera;
                self.torchBtn.selected = self.gatherInfo.openTorch;
                self.beautyBtn.selected = self.gatherInfo.openBeauty;
                self.rotationBtn.selected = self.gatherInfo.isLandscape;
                
                self.controlView.resStr = [NSString stringWithFormat:@"%ldp", self.gatherInfo.resolution];
            };
            
            [self.navigationController pushViewController:gatherSetting animated:YES];
        };
        
        //开始直播并传入输入框的rtmp地址
        _preparingView.startLive = ^(NSString *rtmpUrl) {
            @strongify(self);
            if (![GatherAuthorization verifyCameraAuthorization:self] || ![GatherAuthorization verifyMicrophoneAuthorization:self])
            {
                return;
            }
            
            [self.session stopLive];
            
            if (self.gatherInfo.isLandscape) {
                self.rotationBtn.selected = YES;
                //防止画布随转屏变化的时候画面不匹配
                self.session.running = NO;
                self.session.preView = nil;
                self.isStartingLive = YES;
                [[UIDevice currentDevice] setOrientation:UIDeviceOrientationLandscapeLeft];
            }
            
            if (self.isStartingLive) {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self prepareToStartLiveWithUrl:rtmpUrl];
                });
            } else {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self prepareToStartLiveWithUrl:rtmpUrl];
                });
                [UIView animateWithDuration:0.3 animations:^{
                    self.preparingView.alpha = 0;
                    self.controlView.alpha = 1;
                } completion:^(BOOL finished) {
                }];
            }
        };
    }
    return _preparingView;
}

- (GatherControlView *)controlView
{
    if (!_controlView) {
        _controlView = [[GatherControlView alloc] initWithFrame:self.view.bounds];
        
        _controlView.resStr = [NSString stringWithFormat:@"%ldp", _gatherInfo.resolution];
        
        @weakify(self);
        _controlView.endLive = ^ {
            @strongify(self);
            [self.session stopLive];
            //防止画布随转屏变化的时候画面不匹配
            self.session.running = NO;
            self.session.preView = nil;
            
            if (self.rotationBtn.isSelected) {
                self.rotationBtn.selected = NO;
                self.isEndingLive = YES;
                [[UIDevice currentDevice] setOrientation:UIDeviceOrientationPortrait];
            }
            
            if (self.isEndingLive) {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self prepareToEndLive];
                });
            } else {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self prepareToEndLive];
                });
                [UIView animateWithDuration:0.3 animations:^{
                    self.controlView.alpha = 0;
                    self.preparingView.alpha = 0.4;
                } completion:^(BOOL finished) {
                }];
            }
        };
        
        _controlView.liveBtnClicked = ^ (BOOL start) {
            @strongify(self);
            if (start) {
                LFLiveStreamInfo *stream = [LFLiveStreamInfo new];
                stream.url = self.rtmpUrl;
                [self.session startLive:stream];
            } else {
                [self.session stopLive];
                self.controlView.state = GatherMonitorStop;
            }
        };
    }
    return _controlView;
}

- (MonitorInfo *)monitorInfo
{
    if (!_monitorInfo) {
        _monitorInfo = [MonitorInfo monitorInfo];
    }
    return _monitorInfo;
}

- (UIPinchGestureRecognizer *)pinchGesture
{
    if (!_pinchGesture) {
        _pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
        _pinchGesture.enabled = NO;
    }
    return _pinchGesture;
}

@end
